唔,首先说一下这是在生产环境,生产环境自然是和自己写着玩的环境是不一样的处理方法,生产环境中我们想要的大概是正确、稳定、高效。

Python 配置数据表

jskyzero 2019/01/18

背景概述

是这样的,出于某种目的,现在我需要配置某个表格,表格是这样的,一部分是配置了一些人数属性,另一部分则需要配置关卡与人物属性的对应关系,用于在关卡中使用,关卡中是需要使用到三位角色,目前是将48名角色随机挑选三位给了关卡,但是这样可能会出现三位某些属性相同的角色的情况,为此需要修改配置。

目前支持的方式是,从若干角色中挑选三位,和若干相同关卡对应角色中,随机一种对应,在和相关同(前)学(辈)沟通过以后拒绝在程序部分增加逻辑,希望维持原有配置方式,考虑到之前是采用第一种方式配置,这次需要采用第二种减少挑选范围,扩大同可能挑选对应方式。

但是仔细一想这炸了,这要是枚举出来过百我都懒得配了,之前一个关卡我只写了一行,现在随便要翻若干倍,显然这里靠蛮力是不行的,好在后台逻辑不改,没事,我可以前台手动枚举,这个本质上数学模型还是很简单,具体涉及到一点excel读取,写入,和数据的概率统计处理方面的知识。

模型抽象

再次提及这是在生产环境,甚至没有办法去装某些包,翻了下好歹有个xlrd可以用来读取excel,足够了足够了,暂时是打算写出csv,然后手动拷贝到表中储存,excel中的操作就不太熟悉了,我可以相对模拟输出格式,直接拷贝粘贴,实际上面对几十万行的excel数据,手动修改就会有点不现实了。

那么大概的流程是,读入角色,模拟随机方式,然后去掉不合适的组合,然后写出csv格式文件,然后手工拷贝粘贴至源表格。

编码部分

  • 引入包,常量定义(字符常量已经删除,反正是无意义的字符序列)
import xlrd # for excel read
import csv # for writerows
import itertools # for chain

ROLE_NUM = 10
# static string
EXCEL_PATH = 
OUTPUT_PATH = 
PveRobotConf_Name = 
PveRobotAttrs_Name = 
PveRobotAttrs_ID_Name = 
PveRobotAttrs_JOB_Name =
  • 数据读入

xlrd的方式是先获得book,然后book打开sheet,sheet再获取行、列、或者某个格子,要注意的xlrd只是读取,是没有保存相关接口的。

def read_data():
  # read data
  book = xlrd.open_workbook(EXCEL_PATH);
  PveRobotConf = book.sheet_by_name(PveRobotConf_Name)
  PveRobotAttrs = book.sheet_by_name(PveRobotAttrs_Name)

  sh = PveRobotAttrs
  titles = sh.row_values(0)
  # print("numbers of worksheets: {0}".format(book.nsheets))
  # print("worksheet names: {0}".format(book.sheet_names()))
  # print("{0} {1} {2}".format(sh.name, sh.nrows, sh.ncols))
  data = [sh.col_values(titles.index(PveRobotAttrs_ID_Name),4),
          sh.col_values(titles.index(PveRobotAttrs_JOB_Name),4)]
  return data
  • 生成与筛选

逻辑相对简单,一些对数据切片和匹配的细节就不再展开说了。

def process_each_level(begin, end, data, result, level):
  # python list process
  # transpose
  data = map(list, zip(*data))
  # map to int
  data = map(lambda l : map(int, l), data)
  # get each role between begin and end
  data = map(lambda x : data[x::ROLE_NUM], range(begin, end))
  # transpose make each sub role together
  data = map(list, zip(*data))
  # join together
  # data = itertools.chain(*data)

  # eight role select 4
  for each_select in itertools.combinations(data, 4):
    process_each_select(each_select, result, level)
  return result



def process_each_select(each_select, result, level):
  for each_result in itertools.product(*each_select):
    ids = map(lambda l: l[0], each_result)
    roles = map(lambda l: l[1], each_result)
    # check role
    if (len(set(roles)) == len(roles)):
      each_result = list(itertools.chain(*[[len(result) + 1], [level], [""], ids]))
      result.append(each_result)
  • 输出

因为有大量关卡,这里我们修改config就可以配置关卡与角色起终止一次性生成全部配置。

def process_all():
  result = []
  data = read_data()

  config = [
      [10000, [0,2]],]
  for line in config:
    process_each_level(line[1][0],line[1][1], data, result, line[0]);
  return result


if __name__ == "__main__":
  result = process_all()
  # save to csv file
  with open(OUTPUT_PATH, 'wb') as f:
    csv.writer(f).writerows(result)

总结

唔,中间的删选部分或许可以再抽象一层,但是也没必要,毕竟是能work就好,生成后大概几十万行的配置,如果手工的话感觉我一辈子就没了。

results matching ""

    No results matching ""